import Taro from '@tarojs/taro'
import { API_BASE_URL, USER_API_BASE_URL } from '@/constants/env'
import { clearToken, openLoginPage } from '@/utils/auth'

type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE'

interface RequestOptions<T> {
  url: string
  method?: HttpMethod
  data?: T
  header?: Record<string, string>
  showErrorToast?: boolean
}

interface BusinessResponse<T> {
  errorCode?: string | number
  value?: string
  data?: T
}

const normalizePath = (value: string) =>
  value.startsWith('/') ? value : `/${value}`

const BASE_ROUTE_MAPPINGS: Array<{
  prefix: string
  base: string | undefined
}> = [
  { prefix: '/lowcode-user', base: USER_API_BASE_URL }
]

const resolveBaseUrl = (path: string) => {
  const mapping = BASE_ROUTE_MAPPINGS.find((item) =>
    path.startsWith(item.prefix)
  )
  const targetBase = mapping ? mapping.base : API_BASE_URL
  if (!targetBase) {
    throw new Error('API_BASE_URL 未配置，请设置 TARO_APP_API_BASE_URL')
  }
  return targetBase
}

const combineUrl = (baseUrl: string, relativePath: string) => {
  const normalizedPath = normalizePath(relativePath)
  try {
    const base = new URL(baseUrl)
    const basePath = base.pathname.replace(/\/$/, '')
    const finalPath =
      basePath && normalizedPath.startsWith(basePath)
        ? normalizedPath
        : `${basePath}${normalizedPath}`
    return `${base.origin}${finalPath}`
  } catch (error) {
    const normalizedBase = baseUrl.replace(/\/$/, '')
    return `${normalizedBase}${normalizedPath}`
  }
}

const ensureUrl = (url: string) => {
  if (/^https?:\/\//i.test(url)) {
    return url
  }
  const baseUrl = resolveBaseUrl(url)
  return combineUrl(baseUrl, url)
}

export async function request<ResponseData = any, Payload = any>(
  options: RequestOptions<Payload>
): Promise<ResponseData> {
  const token = Taro.getStorageSync('token')
  const header: Record<string, string> = {
    'Content-Type': 'application/json',
    ...(options.header || {})
  }
  if (token) {
    header.token = token
  }

  try {
    const res = await Taro.request<BusinessResponse<ResponseData>>({
      url: ensureUrl(options.url),
      method: options.method ?? 'POST',
      data: options.data ?? {},
      header
    })

    const payload = res.data
    if (
      typeof payload === 'object' &&
      payload !== null &&
      Object.prototype.hasOwnProperty.call(payload, 'errorCode')
    ) {
      if (payload.errorCode === '0' || payload.errorCode === 0) {
        return (payload.data ?? (payload as any).value) as ResponseData
      }

      if (payload.errorCode === '401' || payload.errorCode === 401) {
        clearToken()
        openLoginPage({ message: '登录状态已失效，请重新登录' })
      }

      const message = payload.value || '请求失败'
      if (options.showErrorToast !== false) {
        Taro.showToast({ title: message, icon: 'none' })
      }
      throw new Error(message)
    }

    return payload as unknown as ResponseData
  } catch (error: any) {
    if (options.showErrorToast !== false) {
      Taro.showToast({
        title: error?.message || '网络开小差了',
        icon: 'none'
      })
    }
    throw error
  }
}
